#include "cutjob.h"

QVector<QString> Cutjob::dic =QVector<QString>();
bool Cutjob::isfir=true;
QSet<QChar> Cutjob::cutch=QSet<QChar>();
QVector<QString> Cutjob::stopset=QVector<QString>();
QSet<QString> Cutjob::block = QSet<QString>();

Cutjob::Cutjob(QString & outtxt ,int outid )
{
   this->txt = QString(outtxt);
   this->id=outid;
}

void Cutjob::run(){
    QVector<QString> ret=this->analy(this->txt,this->dic,this->cutch,this->stopset,this->block);
    QStringList ans(ret.toList());
    emit this->finishwork(id,ans);
}

/*
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QVector<QString> vec = getdic();
    QString txt = gettxt();
    QSet<QChar> cutch = getcut();
    QVector<QString> stopset =getstop();
    QSet<QString> block = getblock();

    QVector<QString> part =analy(txt,vec,cutch,stopset,block);
    show(part);
    return a.exec();
}
*/
void Cutjob::setdic(QVector<QString>& outdic){
    this->dic=QVector<QString>(outdic);
}

void  Cutjob::setstop(QVector<QString> & stop){
    this->stopset =QVector<QString>(stop);
}
QVector<QString> Cutjob::analy(QString & txt,QVector<QString> & dic,QSet<QChar> cutch, QVector<QString> & stopset,QSet<QString> & block ){
    //qDebug()<<"txt: "<<txt;
    QVector<QString> part;
    int len = txt.size();
    for (int i=0;i<len;  ){
        QChar ch=txt.at(i);
      //  std::wstring str =txt.mid(i,5).toStdWString();
       // qDebug()<<"ch: "<<ch;
        if(cutch.contains(ch)){ // sigle check
            //nothing to do;
            //qDebug()<<"cut "<<ch;
            i++;
        }else if (isalpha(ch)){ //token english word
            int len =geteng(i,txt);
            QString wd = txt.mid(i,len);
            if (!this->stopset.contains(wd)){
                addwd(wd,part,block);
            }
            i+=len;
        }else if(ch.isDigit()){ //token a number
            int len = getdig(i,txt);
            QString wd = txt.mid(i,len);
            addwd(wd,part,block);
            i+=len;
        }else{ // check in stop set
            //qDebug()<<"find chinese ";
            int stlen =maxmatch(i,txt,stopset);
            if (stlen){
                i+=stlen;
            }else{
                 // cut word
                int len =maxmatch(i,txt,dic);
                if (len){
                    QString wd =txt.mid(i,len);
                    i+=len;
                    addwd(wd,part,block);
                        //part.push_back(wd);
                }else{ // can not find in the main dic
                    QString wd =txt.mid(i,2);
                    addwd(wd,part,block);
                    i+=2;
                }
            }
        }
    }
    return part;
}

int Cutjob::geteng(int st, QString & txt){
    int len = txt.size();
    int i;
    for (i=0;st+i<len;i++){
        QChar ch = txt.at(st+i);
        if (!isalpha(ch)){
            return i;
        }
    }
    return i;
}
int Cutjob::getdig(int st,QString &txt){
    int len=txt.size();
    int i;
    for (i=0;st+i<len;i++){
        QChar ch = txt.at(st+i);
        if (!ch.isDigit()){
            return i;
        }
    }
    return i;
}
int Cutjob::maxmatch(int st,QString & txt,QVector<QString> & dic ){
    int len = txt.size();
    int tot=dic.size();
   // qDebug()<<"tot: "<<tot;
    int i;
    int hi=tot,lo=0;
    for (i=0;i+st<len;i++){
        QChar ch = txt.at(st+i);
        int nxlo =lobound(lo,hi,i,ch,dic);
        int nxhi =hibound(lo,hi,i,ch,dic);
        //qDebug("nxhi : %d nxlo: %d\n",nxhi,nxlo);
        if (nxlo<nxhi && nxlo>=lo && nxlo<=hi && nxhi>=lo && nxhi<=hi){ // find
            /*
			qDebug()<<"lo: "<<nxlo<<"hi:"<<nxhi;
			for (int j=nxlo;j<nxhi;j++){
				QString tmp = dic[j];
				qDebug()<<tmp;
			}
            */
            lo=nxlo;
            hi=nxhi;
        }else{
            return i;
        }
    }
    return i;
}

void Cutjob::addwd(QString wd,QVector<QString> &part,QSet<QString> & block){
    if (block.contains(wd)){
         part.push_back("***");
    }else{
        part.push_back(wd);
    }
}
void Cutjob::setcut(QSet<QChar>& chcut){
    this->cutch=QSet<QChar>(chcut);
    this->cutch.insert('\n');
    this->cutch.insert('\r');
	this->cutch.insert(' ');
}
void Cutjob::setblock(QSet<QString>& block){
    this->block =QSet<QString>(block);
}
void Cutjob::show(QVector<QString> &part){
    int len=part.size();
    for (int i=0;i<len;i++){
        qDebug()<<part.at(i);
    }
}
bool Cutjob::isalpha(QChar ch){
    return ((ch>='a' && ch<='z')||(ch>='A'&&ch<='Z'));
}


int Cutjob::lobound(int lo ,int hi ,int lev ,QChar ch,QVector<QString> & dic){
    int mid;
    int best=hi;
    while (lo<hi){
        mid=(lo+hi)>>1;
        QString & str=dic[mid];
        //qDebug()<<"dic:   "<<str;
        if (lev<str.size()){
            QChar aim = str.at(lev);
            if (aim<ch){
                lo=mid+1;
            }else if (aim==ch){
                best=qMin(best,mid);
                hi=mid-1;
            }else if (aim>ch){
                hi=mid-1;
            }
        }else{
            //lo=mid+1;
            hi=mid;
        }
    }
    return best;
}
int Cutjob::hibound(int lo ,int hi ,int lev ,QChar ch,QVector<QString> & dic ){
    int mid;
    int best=hi;
    while (lo<hi){
        mid=(lo+hi)>>1;
        QString str=dic.at(mid);
        if (lev<str.size()){
            QChar aim = str.at(lev);
            if (aim<ch){
                lo=mid+1;
            }else if (aim==ch){
                lo=mid+1;
            }else if (aim>ch){
                best=qMin(best,mid);
                hi=mid-1;
            }
        }else{
            //lo=mid+1;
            hi=mid;
        }
    }
    return best;
}
